#ifndef INCLUDE_DAO_BASE_H_
#define INCLUDE_DAO_BASE_H_
#include <iostream>
#include <list>
#include <memory>
#include <string>
#include <vector>

/**
 * @brief 模型中数据对外操作接口
 *
 * @tparam ModelType 模型类型
 */
template <typename ModelType>
class SingleElemMsgBase {
 public:
  virtual ~SingleElemMsgBase() = default;
  virtual void operator()(ModelType *obj) const = 0;
};

/**
 * @brief 模型数据单个成员存储类
 *
 * @tparam ModelType 模型类型
 * @tparam ElemType 单个数据类型
 */
template <typename ModelType, typename ElemType>
class SingleElemMsg : public SingleElemMsgBase<ModelType> {
 public:
  SingleElemMsg(ElemType ModelType::*pointer, std::string name,
                std::string sql_name, std::string type)
      : field_pointer(pointer),
        field_name(name),
        field_sql_name(sql_name),
        sql_type(type) {}

  void operator()(ModelType *obj) const override {
    std::cout << "field_name = " << field_name
              << " ;field_value = " << obj->*field_pointer
              << " ; sql_name = " << field_sql_name
              << " ; sql_type = " << sql_type << " ;" << std::endl;
  }

 private:
  ElemType ModelType::*field_pointer;
  std::string field_name;
  std::string field_sql_name;
  std::string sql_type;
};

/**
 * @brief 存储模型数据
 *
 * @tparam ModelType 模型类型
 */
template <typename ModelType>
class ElemMsgs {
 public:
  template <typename ElemType>
  void RegisterField(ElemType ModelType::*pointer, std::string name,
                     std::string sql_name, std::string type) {
    msgs.push_back(std::make_shared<SingleElemMsg<ModelType, ElemType>>(
        pointer, name, sql_name, type));
  }

  void operator()(ModelType *obj) const {
    for (const auto &msg : msgs) {
      (*msg)(obj);
    }
  }

 private:
  std::vector<std::shared_ptr<SingleElemMsgBase<ModelType>>> msgs;
};

struct MyClass1 {
  int id;
  double score;
  std::string name;
};

class DaoMyClass1 {
 public:
  DaoMyClass1() {
    elemMsgs.RegisterField(&MyClass1::id, "id", "ID", "INT");
    elemMsgs.RegisterField(&MyClass1::score, "score", "SCORE", "DOUBLE");
    elemMsgs.RegisterField(&MyClass1::name, "name", "NAME", "VARCHAR(40)");
    MyClass1 simple{2, 2.2, "2.22"};
    elemMsgs(&simple);
  }
  static void Insert(MyClass1 *obj) {}
  static void Delete(MyClass1 *obj) {}
  static void Update(MyClass1 *obj) {}
  static std::list<MyClass1 *> Select(MyClass1 *obj, int cond);

 private:
  ElemMsgs<MyClass1> elemMsgs;
};

#endif  // INCLUDE_DAO_BASE_H_
